#include <iostream>
#include <math.h>
#include <string.h>
#include <unistd.h>

using namespace std;

// Include GLEW
#include <GL/glew.h>

// Include GLFW
#include <GL/glfw.h>

// Include GLUT
#include <GL/glut.h>

// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtx/norm.hpp>

using namespace glm;

#include "shader.hpp"
#include "Animation.hpp"

#ifndef GRAPHICSENGINE_HPP
#define GRAPHICSENGINE_HPP

#define uint unsigned int

class MPVStack{
private:
    mat4 MPV[30];
    int firstMPV;

public:
    MPVStack();

    int empty();
    int full();

    mat4 *lookFirst();
    int add(mat4 _MPV);
    int take();
};

class ChildStack{
private:
    uint child[30];
    int firstChild;

public:
    ChildStack();

    int empty();
    int full();

    uint lookFirst();
    int addToFirst();
    int add(uint _child);
    int take();
};

//Bones moels in GPU
class BMG{
private:
    BVH *bvh;

    void loadBoneToGPU(JOINT *joint);
    void loadBonesToGPU();

public:
    GLuint GPUVertexBuffer[30];
    GLuint GPUColorsBuffer[30];

    BMG(BVH *_bvh);
};



class GraphicEngine{
private:
    BVH bvh;
    BMG *bmg;

    GLuint programID;
    GLuint VertexArrayID;

    mat4 Projection;
    mat4 View;

    int camera;

    int frameCount;
    float fps;
    int currentTime, previousTime;

    int initWinodw();
    void compileShaders();

    void loadBoneToGPU(GLuint *GPUVertexBuffer, GLuint *GPUColorsBuffer, vec3 offset);

    void drawJOINT(JOINT *joint,
                    mat4 *lastMVP,
                    GLuint MatrixID,
                    uint frame,
                    GLuint GPUVertexBuffer,
                    GLuint GPUColorsBuffer);

    void drawBVH(mat4 MPV, GLuint MatrixID, int frame);
    mat4 getHeadCamera(int frame);

    GLuint VBSurface;
    GLuint VCSurface;
    void loadSurfaceToGPU(int plane);
    void drawSurface(mat4 MPV, GLuint MatrixID);

    void calculateFPS();
public:
    GraphicEngine();

    void graphicEngineLoop();
    void destroyWindow();
};

#endif
